/**

 **/

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "etu_timer.h"
#include "error_code.h"

#include "character_module.h"
#include "Bsp_Delay.h"

#define DIR_OUT	0
#define DIR_IN	1

//#define CLOCK_FREQ	4500000/2
//	#define CLOCK_FREQ	4500000
/*
120M / 32 = 3.75M
*/

#define CLOCK_FREQ	(uint32_t)(4.5 * 1000 * 1000)
extern uint32_t SystemCoreClock;

static uint32_t CharacterModule_GetFreq(void){
	
#if 1
	if(SystemCoreClock > 72000000U){
		return SystemCoreClock / 32;
	}
	
	return SystemCoreClock / 16;
#else
	return SystemCoreClock / 32;
#endif 
}


#if 0
extern hardware_module_t STM32_USART3;
extern hardware_module_t STM32_USART2;
extern hardware_module_t STM32_USART1;
#endif 

extern hardware_module_t SmartCardUsarts[1];

static character_module_t char_module[1] =
{
    {
        &SmartCardUsarts[0], //hw
        0,			//max_retry
        DIRECT_BYTE,//byte_direction
        0x11,		//FiDi
        0x10,		//opposite_guardtime
        DIR_IN,		//transmist_direction
    },
    
#if 0
    {
        &STM32_USART2, //hw
        0,			//max_retry
        DIRECT_BYTE,//byte_direction
        0x11,		//FiDi
        0x10,		//opposite_guardtime
        DIR_IN,		//transmist_direction
    },

    {
        &STM32_USART1, //hw
        0,			//max_retry
        DIRECT_BYTE,//byte_direction
        0x11,		//FiDi
        0x10,		//opposite_guardtime
        DIR_IN, 	//transmist_direction
    }
#endif 
};

character_module_t *CharacterModule[1] =
{
    char_module,
#if 0
    char_module + 1,
    char_module + 2
#endif 
};


void CharacterModule_SetCharDuration(character_module_t *module, uint8_t char_duration)
{
    HardwareModule_SetCharDuration(module->hw, char_duration);
}

void CharacterModule_SetETU(character_module_t *module, uint8_t FiDi)
{
    HardwareModule_SetETU(module->hw, FiDi);
    module->FiDi = FiDi;
}

void CharacterModule_ConfigByteDirection(character_module_t *module, uint8_t direction)
{
    HardwareModule_SetByteDirection(module->hw, direction);
    module->byte_direction = direction;
}

void CharacterModule_SetByteDirect(character_module_t *module)
{
    CharacterModule_ConfigByteDirection(module, DIRECT_BYTE);
}

void CharacterModule_SetByteReverse(character_module_t *module)
{
    CharacterModule_ConfigByteDirection(module, REVERSE_BYTE);
}

void CharacterModule_SetStopbits(character_module_t *module, uint8_t stopbits)
{
    HardwareModule_SetStopbits( module->hw, stopbits);
}

void CharacterModule_SetOppositiveGuardtime(character_module_t *module, uint16_t opposite_guardtime)
{
    module->opposite_guardtime = opposite_guardtime;
}


void CharacterModule_ConfigRetransmit(character_module_t *module, uint8_t retransmit_times)
{
    hardware_module_t * hw = module->hw;

    if(retransmit_times != 0)
    {
        HardwareModule_NAKEnable(hw);
        //HardwareModule_SetStopbits(hw, 2);
    }
    else
    {
        HardwareModule_NAKDisable(hw);
        //HardwareModule_SetStopbits(hw, 1);
    }

    module->retransmit_times = retransmit_times;
}

uint8_t CharacterModule_IsRetransmitEnable(character_module_t *module)
{
    return module->retransmit_times != 0;
}

void CharacterModule_TimerDelay(character_module_t *module, uint32_t etu)
{
    ETUTimer_Wait(etu, module->FiDi);
}

void CharacterModule_TimerStart(character_module_t *module, uint32_t etu)
{
//	    ETUTimer_Start(etu, module->FiDi);
}

void CharacterModule_TimerReset(character_module_t *module)
{
//	    ETUTimer_Reset();
}

void CharacterModule_TimerStop(character_module_t *module)
{
//	    ETUTimer_Stop();
}

static void CharacterModule_OppositGuard(character_module_t *module)
{
    ETUTimer_Wait(module->opposite_guardtime, module->FiDi);
}

uint8_t CharacterModule_SendByte(character_module_t *module, uint8_t byte, uint32_t guard_time)
{
    uint8_t ret;
    uint32_t error_count;

    if(module->transmit_direction != DIR_OUT)
    {
        module->transmit_direction = DIR_OUT;
        CharacterModule_TimerStop(module);
        CharacterModule_OppositGuard(module);
    }

    for(error_count = module->retransmit_times - 1; ; error_count-- ) /*根据规范，只重传5次*/
    {
        ret = HardwareModule_SendByte(module->hw, byte);
		if(module->retransmit_times == 0)
		{	
			break;
		}
		
		ret = HardwareModule_CheckNAK(module->hw);
		
		 if((ret != ERR_SEND) || (error_count == 0))
		 {
			 break;
		 }
		
		CharacterModule_TimerDelay(module, 3);	/*重传字符前延迟3个ETU*/
    }

    if(ret == NO_ERR)
    {
//	    	delay_us(4);
//			BSP_Delay_us(4);
		if(guard_time){
	        CharacterModule_TimerDelay(module, guard_time); /*额外保护时间*/
		}
    }

    return ret;
}


uint8_t CharacterModule_SendData(character_module_t *module,
                                 uint8_t *data, uint32_t data_len, uint32_t guard_time)
{
    uint8_t ret = NO_ERR;
    uint32_t i;


    for(i = 0; i < data_len; i++)
    {
        ret = CharacterModule_SendByte(module, data[i], guard_time);

        if(ret != NO_ERR)
        {
            break;
        }
    }

    return ret;
}


void CharacterModule_Flush(character_module_t *module)
{
    HardwareModule_Flush(module->hw);
}

uint8_t CharacterModule_ReceiveByte(character_module_t *module, uint8_t *receive_byte, uint32_t etu)
{
    uint8_t ret;
    uint32_t error_count;
	uint16_t data;

    if(module->transmit_direction != DIR_IN)
    {
        module->transmit_direction = DIR_IN;
    }
	
	uint32_t clk = ETUTimer_ETU2Clock(etu, module->FiDi);
    for(error_count = module->retransmit_times; ; error_count--)
    {
        ret = HardwareModule_ReceiveByte(module->hw, &data, clk);
//	        CharacterModule_TimerReset(module);
		if(module->retransmit_times == 0)
		{
			break;
		}
		
        if(error_count == 0)	/*EMV 测试要求接收第6次重传的数据，然后下电*/
        {
			ret = ERR_OVER_RETRANSMIT;
			break;
        }
        
        if(ret != ERR_PARITY)
        {
            break;
        }
        //HardwareModule_SoftwareNak(module->FiDi);
    }
	*receive_byte = (uint8_t)data;
    return ret;
}

uint8_t CharacterModule_ReceiveData(character_module_t *module,
                                    uint8_t *receive_buf, uint32_t receive_len, uint32_t wait_time)
{
    uint32_t i;
    uint8_t ret = NO_ERR;

    CharacterModule_TimerStart(module, wait_time);

    for(i = 0; i < receive_len; i++)
    {
        ret = CharacterModule_ReceiveByte(module, receive_buf + i, wait_time);

        if(ret != NO_ERR)
        {
            break;
        }
    }

    return ret;
}

void CharacterModule_Reset(character_module_t *module)
{
	module->transmit_direction = DIR_IN;
	HardwareModule_Reset(module->hw);
//		HardwareModule_SetFrequency(module->hw, CLOCK_FREQ);
}

void CharacterModule_Init(void)
{
	const uint32_t freq = CharacterModule_GetFreq();
	
    HardwareModule_Init();
    HardwareModule_SetFrequency(char_module[0].hw, freq);
//	    HardwareModule_SetFrequency(char_module[1].hw, CLOCK_FREQ);
//	    HardwareModule_SetFrequency(char_module[2].hw, CLOCK_FREQ);
    ETUTimer_Init(freq);
}

#if 1

void HardwareModule_Init(void);

void test_CharacterModule(void)
{
    volatile uint32_t i;
	uint8_t rx;
    uint8_t tx = 0xC0;
	const uint32_t freq = CharacterModule_GetFreq();
    ETUTimer_Init(freq);
	HardwareModule_Init();
    CharacterModule_SetStopbits(char_module, 1);
    CharacterModule_SetCharDuration(char_module, 11);
	CharacterModule_SetETU(char_module, 0x11);

    while(1)
    {
		CharacterModule_SendByte(char_module, 0x55, 0);
		CharacterModule_SendByte(char_module, 0x55, 0);
//			CharacterModule_ReceiveByte(char_module, &rx);
	
        //CharacterModule_SendByte(char_module, 0x55, 0);
        //CharacterModule_SendByte(char_module, 0x55, 0);

#if 0
        CharacterModule_SendByte(char_module, tx, 0);
        CharacterModule_SendByte(char_module, tx, 0);
        CharacterModule_SendByte(char_module, tx, 0);
        CharacterModule_SendByte(char_module, tx, 0);
        CharacterModule_SendByte(char_module, tx, 0);
        CharacterModule_SendByte(char_module, tx, 0);
#endif 

        //CharacterModule_SendByte(char_module, tx, 0);
        //CharacterModule_SendByte(char_module, tx, 254);
        //CharacterModule_SendByte(char_module, tx, 0);
        for(i = 0; i < 0xFFFF; i++)
        {}
    }

}
#endif

/********************************************************************************/

